from flask import current_app, g
from sqlalchemy import and_
from werkzeug.security import generate_password_hash, check_password_hash
import logging

from app.models.car import CarInfo
from app.models.ruel_cost import RuelCost, RuelCostImage
from app.models.road_toll import RoadToll, RoadTollImage
from app.models.parking_rate import ParkingRate, ParkingImage
from common.utils.db import TotalNumberSerializer
from common.utils.image_tools import save_image, get_link
from common.utils.jwt_util import create_token, check_token
from common.utils.backends import AliyunOssStorage
from app import serializer
from marshmallow import (
    fields,
    Schema,
    validates,
    validates_schema,
    ValidationError,
    post_dump,
    post_load,
    pre_load,
    pre_dump,
)

from app.models import db
from app.models.user import User, Role, PermissionPath

ali_oss = AliyunOssStorage()

LOG = logging.getLogger(__name__)


class RoadImagePostQuerySerizlizer(serializer.Schema):
    files = fields.String()
    road_toll = fields.Integer()

    @post_load
    def save_image(self, data, many, *args, **kwargs):
        try:
            data_collection = RoadToll.query.get(data.get("road_toll"))
        except Exception as e:
            raise ValidationError

        # 保存图片

        file = self.context.get("request").files.get("files")
        file_name = save_image(file)

        image = RoadTollImage(file=file_name, road_toll=data_collection.id)

        db.session.add(image)

        db.session.commit()

        return image


class RoadImageIdSerizlizer(serializer.SQLAlchemySchema):
    class Meta:
        model = RoadTollImage
        fields = ["id"]


class RoadImageSerizlizer(serializer.SQLAlchemySchema):
    class Meta:
        model = RoadTollImage
        fields = ["id", "file", "road_toll"]

    @pre_dump
    def image_body(self, data, many, *args, **kwargs):

        data.file = get_link(data.file)

        return data


class ParkingImagePostQuerySerizlizer(serializer.Schema):
    files = fields.String()
    parking = fields.Integer()

    @post_load
    def save_image(self, data, many, *args, **kwargs):
        try:
            data_collection = ParkingRate.query.get(data.get("parking"))
        except Exception as e:
            raise ValidationError

        # 保存图片

        file = self.context.get("request").files.get("files")
        file_name = save_image(file)
        image = ParkingImage(file=file_name, parking=data_collection.id)

        db.session.add(image)

        db.session.commit()

        return image


class ParkingImageIdSerizlizer(serializer.SQLAlchemySchema):
    class Meta:
        model = ParkingImage
        fields = ["id"]


class ParkingImageSerizlizer(serializer.SQLAlchemySchema):
    class Meta:
        model = ParkingImage
        fields = ["id", "file", "parking"]

    @pre_dump
    def image_body(self, data, many, *args, **kwargs):

        data.file = get_link(data.file)

        return data


class RuelImagePostQuerySerizlizer(serializer.Schema):
    files = fields.String()
    ruel_cost = fields.Integer()

    @post_load
    def save_image(self, data, many, *args, **kwargs):
        try:
            data_collection = RuelCost.query.get(data.get("ruel_cost"))
        except Exception as e:
            raise ValidationError

        # 保存图片

        file = self.context.get("request").files.get("files")
        file_name = save_image(file)
        image = RuelCostImage(file=file_name, ruel_cost=data_collection.id)

        db.session.add(image)

        db.session.commit()

        return image


class RuelImageIdSerizlizer(serializer.SQLAlchemySchema):
    class Meta:
        model = RuelCostImage
        fields = ["id"]


class RuelImageSerizlizer(serializer.SQLAlchemySchema):
    class Meta:
        model = RuelCostImage
        fields = ["id", "file", "ruel_cost"]

    @pre_dump
    def image_body(self, data, many, *args, **kwargs):

        data.file = get_link(data.file)

        return data


class CarBodySerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = CarInfo
        fields = ["id", "car_num", "asset_code", "vin_num", "create_time"]


class RuelPutSerializer(serializer.SQLAlchemySchema):
    id = fields.Integer()

    class Meta:
        model = RuelCost
        fields = [
            "id",
            "mileage",
            "oil_quantity",
            "price",
            "total_price",
            "engineer",
            "remarks",
            "create_time",
        ]

    @pre_load
    def befor_create_collection(self, data, many, **kwargs):
        body_dict = {}
        for key, value in data.items():
            if value:
                if key == "create_time" or key == "update_time":
                    value = value.split(".")[0]
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_Ruel_info(self, data, many, **kwargs):
        ruel_id = data.pop("id")

        # 更新
        try:
            Ruel_info = RuelCost.query.filter(RuelCost.id == ruel_id).update(data)
        except Exception as e:
            raise e

        db.session.commit()
        return Ruel_info


class RuelIdDeletedSerializer(serializer.Schema):
    id = fields.Integer()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_ruel_info(self, data, many, **kwargs):
        # 删除
        try:
            ruel_info = RuelCost.query.get(data.get("id"))
        except Exception as e:
            raise e
        ruel_info.deleted = True
        db.session.commit()

        return ruel_info


class RuelCreateQuerySerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = RuelCost
        fields = [
            "mileage",
            "oil_quantity",
            "price",
            "total_price",
            "engineer",
            "remarks",
            "create_time",
            "car",
            "user",
        ]

    @pre_load
    def befor_create_collection(self, data, many, **kwargs):
        body_dict = {}
        if g.user_id:
            body_dict["user"] = g.user_id
        for key, value in data.items():
            if value:
                if key == "create_time" or key == "update_time":
                    value = value.split(".")[0]
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_ruel_info(self, data, many, **kwargs):
        # 保存
        Ruel_info = RuelCost(**data)

        db.session.add(Ruel_info)

        db.session.commit()

        return Ruel_info


class RuelListQuerySerializer(serializer.Schema):
    page = fields.Integer()
    per_page = fields.Integer()
    start_time = fields.String()
    end_time = fields.String()
    car_num = fields.String()

    class Meta:
        model = RuelCost
        fields = [
            "page",
            "per_page",
            "mileage",
            "oil_quantity",
            "price",
            "total_price",
            "engineer",
            "remarks",
            "create_time",
            "start_time",
            "end_time",
            "car_num",
        ]

    @pre_load
    def befor_action(self, data, many, **kwargs):
        body_dict = {}
        for key, value in data.items():
            if value:
                if key in ["start_time", "end_time"]:
                    value = data[key].split("T")[0].replace('"', "")
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def list_info(self, data, many, **kwargs):
        # 报存数据对象
        page = data.pop("page", 1)
        per_page = data.pop("per_page", 10)
        ruel_query = []
        if data.get("car_num"):
            ruel_query.append(CarInfo.car_num.contains(data.get("car_num")))

        if data.get("start_time") and data.get("end_time"):
            ruel_query.append(
                and_(
                    db.cast(RuelCost.create_time, db.DATE)
                    >= db.cast(data.get("start_time"), db.DATE),
                    db.cast(RuelCost.create_time, db.DATE)
                    <= db.cast(data.get("end_time"), db.DATE),
                )
            )

        elif data.get("start_time"):

            ruel_query.append(
                db.cast(RuelCost.create_time, db.DATE) >= db.cast(data.get("start_time"), db.DATE)
            )

        elif data.get("end_time"):

            ruel_query.append(
                db.cast(RuelCost.create_time, db.DATE) <= db.cast(data.get("end_time"), db.DATE)
            )

        ruel_infos = (
            RuelCost.query.join(CarInfo, CarInfo.id == RuelCost.car)
            .filter(RuelCost.deleted == False, *ruel_query)
            .order_by(RuelCost.id.desc())
            .paginate(page, per_page)
        )
        return ruel_infos.items, ruel_infos.total


class RuelIdSerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = RuelCost
        fields = ["id"]


class RuelBodySerializer(serializer.SQLAlchemySchema):
    cars = fields.Nested(CarBodySerializer())
    images = fields.Nested(RuelImageSerizlizer(many=True))

    class Meta:
        model = RuelCost
        fields = [
            "id",
            "mileage",
            "oil_quantity",
            "price",
            "total_price",
            "engineer",
            "remarks",
            "create_time",
            "cars",
            "images",
        ]


class RuelDataSerializer(serializer.Schema, TotalNumberSerializer):
    data = fields.Nested(RuelBodySerializer(many=True))


class RoadPutSerializer(serializer.SQLAlchemySchema):
    id = fields.Integer()

    class Meta:
        model = RoadToll
        fields = [
            "id",
            "enterance",
            "export",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "car",
        ]

    @pre_load
    def befor_create_collection(self, data, many, **kwargs):
        body_dict = {}
        for key, value in data.items():
            if value:
                if key == "create_time" or key == "update_time":
                    value = value.split(".")[0]
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_info(self, data, many, **kwargs):
        ruel_id = data.pop("id")

        # 更新
        try:
            Ruel_info = RoadToll.query.filter(RoadToll.id == ruel_id).update(data)
        except Exception as e:
            raise e

        db.session.commit()
        return Ruel_info


class RoadIdDeletedSerializer(serializer.Schema):
    id = fields.Integer()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_info(self, data, many, **kwargs):
        # 删除
        try:
            data = RoadToll.query.get(data.get("id"))
        except Exception as e:
            raise e
        data.deleted = True
        db.session.commit()

        return data


class RoadCreateQuerySerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = RoadToll
        fields = [
            "enterance",
            "export",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "car",
            "user",
        ]

    @pre_load
    def befor_create_collection(self, data, many, **kwargs):
        body_dict = {}
        if g.user_id:
            body_dict["user"] = g.user_id
        for key, value in data.items():
            if value:
                if key == "create_time" or key == "update_time":
                    value = value.split(".")[0]
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_info(self, data, many, **kwargs):
        # 保存
        info = RoadToll(**data)

        db.session.add(info)

        db.session.commit()

        return info


class RoadListQuerySerializer(serializer.Schema):
    page = fields.Integer()
    per_page = fields.Integer()
    car_num = fields.String()
    start_time = fields.String()
    end_time = fields.String()

    class Meta:
        model = RoadToll
        fields = [
            "id",
            "road_name",
            "enterance",
            "export",
            "price",
            "price_total",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "page",
            "per_page",
            "car_num",
            "start_time",
            "end_time",
        ]

    @pre_load
    def befor_action(self, data, many, **kwargs):

        body_dict = {}
        for key, value in data.items():
            if value:
                if key in ["start_time", "end_time"]:
                    value = data[key].split("T")[0].replace('"', "")
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def list_info(self, data, many, **kwargs):

        road_query = []

        if data.get("start_time") and data.get("end_time"):
            road_query.append(
                and_(
                    db.cast(RoadToll.create_time, db.DATE)
                    >= db.cast(data.get("start_time"), db.DATE),
                    db.cast(RoadToll.create_time, db.DATE)
                    <= db.cast(data.get("end_time"), db.DATE),
                )
            )

        elif data.get("start_time"):

            road_query.append(
                db.cast(RoadToll.create_time, db.DATE) >= db.cast(data.get("start_time"), db.DATE)
            )

        elif data.get("end_time"):

            road_query.append(
                db.cast(RoadToll.create_time, db.DATE) <= db.cast(data.get("end_time"), db.DATE)
            )

        # 报存数据对象
        page = data.pop("page", 1)
        per_page = data.pop("per_page", 10)
        info = (
            RoadToll.query.join(CarInfo, CarInfo.id == RoadToll.car)
            .filter(RoadToll.deleted == False, *road_query)
            .order_by(RoadToll.id.desc())
            .paginate(page, per_page)
        )
        return info.items, info.total


class RoadIdSerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = RoadToll
        fields = ["id"]


class RoadBodySerializer(serializer.SQLAlchemySchema):
    cars = fields.Nested(CarBodySerializer())
    images = fields.Nested(RoadImageSerizlizer(many=True))

    class Meta:
        model = RoadToll
        fields = [
            "id",
            "road_name",
            "enterance",
            "export",
            "price_total",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "cars",
            "images",
        ]


class RoadDataSerializer(serializer.Schema, TotalNumberSerializer):
    data = fields.Nested(RoadBodySerializer(many=True))


class ParkingPutSerializer(serializer.SQLAlchemySchema):
    id = fields.Integer()

    class Meta:
        model = ParkingRate
        fields = [
            "id",
            "parking",
            "enter_time",
            "out_time",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
        ]

    @pre_load
    def befor_create_collection(self, data, many, **kwargs):
        body_dict = {}
        for key, value in data.items():
            if value:
                if key in ["create_time", "update_time", "enter_time", "out_time"]:
                    value = value.split(".")[0]
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_info(self, data, many, **kwargs):
        ruel_id = data.pop("id")

        # 更新
        try:
            info = ParkingRate.query.filter(ParkingRate.id == ruel_id).update(data)
        except Exception as e:
            raise e

        db.session.commit()
        return info


class ParkingIdDeletedSerializer(serializer.Schema):
    id = fields.Integer()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_info(self, data, many, **kwargs):
        # 删除
        try:
            data = ParkingRate.query.get(data.get("id"))
        except Exception as e:
            raise e
        data.deleted = True
        db.session.commit()

        return data


class ParkingCreateQuerySerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = ParkingRate
        fields = [
            "parking",
            "enter_time",
            "out_time",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "car",
            "user",
        ]

    @pre_load
    def befor_create_collection(self, data, many, **kwargs):
        body_dict = {}
        if g.user_id:
            body_dict["user"] = g.user_id

        for key, value in data.items():
            if value:
                if key in ["create_time", "update_time", "enter_time", "out_time"]:
                    value = value.split(".")[0]
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_info(self, data, many, **kwargs):
        # 保存
        info = ParkingRate(**data)

        db.session.add(info)

        db.session.commit()

        return info


class ParkingListQuerySerializer(serializer.Schema):
    page = fields.Integer()
    per_page = fields.Integer()
    car_num = fields.String()
    start_time = fields.String()
    end_time = fields.String()

    class Meta:
        model = ParkingRate
        fields = [
            "id",
            "parking",
            "enter_time",
            "out_time",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "start_time",
            "end_time",
            "car_num",
        ]

    @pre_load
    def befor_action(self, data, many, **kwargs):
        body_dict = {}
        for key, value in data.items():
            if value:
                if key in ["start_time", "end_time"]:
                    value = data[key].split("T")[0].replace('"', "")
                body_dict[key] = value

        return body_dict

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def list_info(self, data, many, **kwargs):

        road_query = []

        if data.get("start_time") and data.get("end_time"):
            road_query.append(
                and_(
                    db.cast(RoadToll.create_time, db.DATE)
                    >= db.cast(data.get("start_time"), db.DATE),
                    db.cast(RoadToll.create_time, db.DATE)
                    <= db.cast(data.get("end_time"), db.DATE),
                )
            )

        elif data.get("start_time"):

            road_query.append(
                db.cast(RoadToll.create_time, db.DATE) >= db.cast(data.get("start_time"), db.DATE)
            )

        elif data.get("end_time"):

            road_query.append(
                db.cast(RoadToll.create_time, db.DATE) <= db.cast(data.get("end_time"), db.DATE)
            )

        # 报存数据对象
        page = data.pop("page", 1)
        per_page = data.pop("per_page", 10)
        info = (
            ParkingRate.query.join(CarInfo, CarInfo.id == ParkingRate.car)
            .filter(ParkingRate.deleted == False, *road_query)
            .order_by(ParkingRate.id.desc())
            .paginate(page, per_page)
        )
        return info.items, info.total


class ParkingIdSerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = ParkingRate
        fields = ["id"]


class ParkingBodySerializer(serializer.SQLAlchemySchema):
    cars = fields.Nested(CarBodySerializer())
    images = fields.Nested(ParkingImageSerizlizer(many=True))

    class Meta:
        model = ParkingRate
        fields = [
            "id",
            "parking",
            "enter_time",
            "out_time",
            "price",
            "deleted",
            "engineer",
            "remarks",
            "create_time",
            "cars",
            "images",
        ]


class ParkingDataSerializer(serializer.Schema, TotalNumberSerializer):
    data = fields.Nested(ParkingBodySerializer(many=True))
